﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
using System.ComponentModel;

namespace Nizm0.QOT.Library.Objects
{
    [Serializable]
    public class Query : IExportable, IXmlSerializable
    {
        private string _queryString;
        private IProcedureInfo _parent;
        private List<Variable> _listOfVariable;
        private DateTime? _startDate;
        /// <summary>
        /// \server\base\shema\table
        /// </summary>
        private string _foundPath;
        private int? _duration;
        private int? _reads;
        private int? _writes;
        private int? _cpu;
        private bool _exported;


        public enum QueryType { Founded, Created };

        #region Values
        [XmlIgnore()]
        [CategoryAttribute("Misc")]
        public string QueryString
        {
            get { return _queryString; }
            set { _queryString = value; }
        }
        [XmlIgnore()]
        [CategoryAttribute("Misc")]
        public IProcedureInfo Parent
        {
            get { return _parent; }
            set { _parent = value; }
        }
        [CategoryAttribute("Misc")]
        public string FoundPath
        {
            get { return _foundPath; }
            set { _foundPath = value; }
        }
        [XmlIgnore()]
        [CategoryAttribute("Misc")]
        public List<Variable> ListOfVariable
        {
            get { return _listOfVariable; }
        }
        [XmlIgnore()]
        [CategoryAttribute("Misc")]
        public DateTime? StartDate
        {
            get { return _startDate; }
            set { _startDate = value; }
        }
        [XmlIgnore()]
        [CategoryAttribute("Misc")]
        public QueryType Type
        {
            get;
            set;
        }
        #endregion

        public Query(ProcedureInfo parent, string query, int? duration, int? reads, int? writes, int? cpu, DateTime? stardate)
            : this(parent, query)
        {
            _duration = duration;
            _reads = reads;
            _writes = writes;
            _cpu = cpu;
            _startDate = stardate;
        }

        public Query(ProcedureInfo parent, string query)
        {
            _parent = parent;
            if (!string.IsNullOrWhiteSpace(query))
            {
                _queryString = query;
                _listOfVariable = GetVariable(query);
            }
        }

        public Query()
        { }

        private List<Variable> GetVariable(string query)
        {
            //char[] blockbeginchars = { '\'', '\"', '[', '{', '(', '<' };
            //char[] blockendchars = { '\'', '\"', ']', '}', ')', '>' };
            string patternDeclare = @"declare\s+(?<Name>(\@[a-zA-Z0-9]+))\s+(?<Type>([a-zA-Z]+(\([0-9]+\s*,\s*[0-9]*\))*))";
            //string pattenrnproc =  @"(exec)\s+[a-zA-Z0-9\.]*" + _parent.Name;
            //string patternvariable = @"(?<Name>(\@[a-zA-Z]*))\s=\s(?<Value>('[0-9]+')|([0-9]+)|('<.*>'))";//(?<Data>[0-9]{4}-[0-9]{2}-[0-9]{2})[\\s\\|\\s]*(?<Project>[^\\||^\\s|^\\r]+)[\\s\\|\\s]*(?<User>[A-Z]{1}[^\\s]*\\s[A-Z]{1}[^\\s|\\|]*){0,}[\\s\\|\\s]*(?<Comment>[^\\r]+)" ;

            List<Variable> mylist = new List<Variable>();
            try
            {
                VariableFromQuery tmpv;
                int x = 0;
                System.Text.RegularExpressions.Regex reg = new System.Text.RegularExpressions.Regex(patternDeclare, System.Text.RegularExpressions.RegexOptions.IgnoreCase);
                foreach (System.Text.RegularExpressions.Match match in reg.Matches(query))
                {
                    tmpv = new VariableFromQuery(match.Groups["Name"].Value, match.Groups["Type"].Value, true);
                    mylist.Add(tmpv);
                }
                x = query.IndexOf(_parent.Name) + _parent.Name.Length;
                while (x < query.Length)
                {
                    int point = 0;
                    tmpv = new VariableFromQuery();
                    while (char.IsWhiteSpace(query[x]))
                        x++;
                    if (query[x] == '@')
                    {
                        point = 0;
                        int space = query.IndexOf(' ', x);
                        int equals = query.IndexOf('=', x);
                        if (space > 0 && equals > 0)
                            if (space < equals)
                                point = space;
                            else
                                point = equals;
                        else
                            break;
                        if (!mylist.Exists(v => v.Name == query.Substring(x, point - x)))
                            tmpv.Name = query.Substring(x, point - x);
                        x = equals + 1;
                    }
                    while (char.IsWhiteSpace(query[x]))
                        x++;
                    switch (query[x])
                    {
                        case 'N':
                            {
                                point = x;
                                while (query[point + 1] == '\'' && query[point + 2] != '\'')
                                {
                                    point = query.IndexOf('\'', x + 3);
                                    if (query[point] == '\'' && query[point + 1] != '\'')
                                    {
                                        tmpv.Value = query.Substring(x, point - x + 1);
                                        x = point;
                                    }
                                }
                                x++;
                                break;
                            }
                        case '\'':
                            {
                                point = x;
                                while (query[point] == '\'' && query[point + 1] != '\'')
                                {
                                    point = query.IndexOf('\'', x + 2);
                                    if (query[point] == '\'' && query[point + 1] != '\'')
                                    {
                                        tmpv.Value = query.Substring(x, point - x + 1);
                                        x = point;
                                    }
                                }
                                x++;
                                break;
                            }
                        default:
                            {
                                point = x;
                                if (char.IsDigit(query[point]))
                                {
                                    while (char.IsDigit(query[point]))
                                    {
                                        point ++;
                                    }
                                    tmpv.Value = query.Substring(x, point - x);
                                }
                                x ++;
                                break;
                            }
                            
                    }
                    if (!string.IsNullOrWhiteSpace(tmpv.Name) || !string.IsNullOrWhiteSpace(tmpv.Value))
                        mylist.Add(tmpv);
                }

                //char[] charForSplit = { '\'' };
                //string[] strlist = query.Split(charForSplit, StringSplitOptions.RemoveEmptyEntries);
                //foreach (string tmpstr in strlist)
                //{
                //    mylist.Add(new VariableFromQuery(tmpstr));
                //}
            }
            catch (Exception ex)
            {
                throw ex;
            }
            finally
            {
            }

            return mylist;
        }

        public override string ToString()
        {
            return _queryString;
        }

        public System.Xml.Schema.XmlSchema GetSchema()
        {
            throw new NotImplementedException();
        }

        public void ReadXml(XmlReader reader)
        {
            reader.MoveToContent();

            int i;
            _queryString = reader.GetAttribute("QueryString");
            int.TryParse(reader.GetAttribute("Duration"), out i);
            _duration = i;
            int.TryParse(reader.GetAttribute("Reads"), out i);
            _reads = i;
            int.TryParse(reader.GetAttribute("Writes"), out i);
            _writes = i;
            DateTime d;
            DateTime.TryParse(reader.GetAttribute("StarDate"), out d);
            _startDate = d;
            int.TryParse(reader.GetAttribute("CPU"), out i);
            _cpu = i;
            bool.TryParse(reader.GetAttribute("Exported"), out _exported);
            _foundPath = reader.GetAttribute("FoundPath");

            Boolean isEmptyElement = reader.IsEmptyElement; // (1)
            reader.ReadStartElement();
            if (!isEmptyElement) // (1)
            {
                reader.ReadEndElement();
            }
        }

        public void WriteXml(XmlWriter writer)
        {
            writer.WriteAttributeString("QueryString", _queryString);
            writer.WriteAttributeString("Duration", _duration.ToString());
            writer.WriteAttributeString("Reads", _reads.ToString());
            writer.WriteAttributeString("Writes", _writes.ToString());
            writer.WriteAttributeString("StarDate", _startDate.ToString());
            writer.WriteAttributeString("CPU", _cpu.ToString());
            writer.WriteAttributeString("Exported", _exported.ToString());
            writer.WriteAttributeString("FoundPath", _foundPath);
        }

        public string Identification
        {
            get
            {
                return _queryString;
            }
            set
            {
                _queryString = value;
            }
        }

        public bool Exported
        {
            get
            {
                return _exported;
            }
            set
            {
                _exported = value;
            }
        }
    }
}
